# -*- coding: utf-8 -*-
# @Author   : zxc19
# @Time     : 2023/7/6 20:53
# @FileName : compressor.py
# @Desc     : 请输入功能模块描述
import os
import zipfile
from pathlib import Path
from typing import List

from loguru import logger


class Compressor:
    @staticmethod
    def compress(output_filepath: str | Path, files_and_dirs: str | Path | List[str | Path]):
        """
        将文件和目录列表压缩为具有层次结构的 ZIP 文件。
        :param output_filepath: 压缩包应保存的文件夹路径。包括“ .zip”扩展名。
        :param files_and_dirs: 要压缩的文件和目录路径对象或列表。
        :return:
        """
        try:
            # 打开 ZIP 文件以供写入
            with zipfile.ZipFile(
                    output_filepath,
                    mode="w",
                    compression=zipfile.ZIP_DEFLATED
            ) as zip_file:
                # 处理只有一个情况
                if isinstance(files_and_dirs, str | Path):
                    files_and_dirs = [files_and_dirs]
                # 遍历进行添加压缩
                for path in files_and_dirs:
                    Compressor._add_file_or_directory(zip_file, path)
                logger.info(f'压缩{files_and_dirs}到{output_filepath}完成')
            return True
        except Exception as e:
            logger.error(f'压缩{files_and_dirs}到{output_filepath}失败===>{e}')
            return False

    @staticmethod
    def _add_file_or_directory(zip_file: zipfile.ZipFile, path: str | Path):
        """
        添加文件或目录
        :param zip_file:
        :param path:
        :return:
        """
        path = Path(path)
        if path.is_file():
            # 相对路径写入
            zip_file.write(path, path.relative_to(path.parent))
        elif path.is_dir():
            for root, dirs, files in os.walk(path):
                for file in files:
                    # 相对路径写入
                    file_path = Path(root).joinpath(file)
                    relative_path = file_path.relative_to(path.parent)
                    zip_file.write(file_path, arcname=relative_path)
        else:
            logger.warning(f'文件或目录【{str(path)}】不存在，跳过继续压缩其他文件或目录')
